#include "records.h"
#include "utility.h"
#include <sstream>
#include <ctime>

#include <iostream>

using namespace std;

namespace stdf {

#define PUSH(name) fields.push_back( toString(name))

    string recordTypeToString( RecordType recType) {
        string recTypeString;

        switch(recType) {
          case FAR: recTypeString = "FAR"; break;
          case ATR: recTypeString = "ATR"; break;
          case MIR: recTypeString = "MIR"; break;
          case MRR: recTypeString = "MRR"; break;
          case PCR: recTypeString = "PCR"; break;
          case HBR: recTypeString = "HBR"; break;
          case SBR: recTypeString = "SBR"; break;
          case PMR: recTypeString = "PMR"; break;
          case PGR: recTypeString = "PGR"; break;
          case PLR: recTypeString = "PLR"; break;
          case RDR: recTypeString = "RDR"; break;
          case SDR: recTypeString = "SDR"; break;
          case WIR: recTypeString = "WIR"; break;
          case WRR: recTypeString = "WRR"; break;
          case WCR: recTypeString = "WCR"; break;
          case PIR: recTypeString = "PIR"; break;
          case PRR: recTypeString = "PRR"; break;
          case TSR: recTypeString = "TSR"; break;
          case PTR: recTypeString = "PTR"; break;
          case MPR: recTypeString = "MPR"; break;
          case FTR: recTypeString = "FTR"; break;
          case BPS: recTypeString = "BPS"; break;
          case EPS: recTypeString = "EPS"; break;
          case GDR: recTypeString = "GDR"; break;
          case DTR: recTypeString = "DTR"; break;
            default: recTypeString = "";
        };

        return recTypeString;
    }

    string recordTypeToString( U1 type, U1 subType) {
        string recTypeString;

        switch( type*100 + subType) {
          case FAR: recTypeString = "FAR"; break;
          case ATR: recTypeString = "ATR"; break;
          case MIR: recTypeString = "MIR"; break;
          case MRR: recTypeString = "MRR"; break;
          case PCR: recTypeString = "PCR"; break;
          case HBR: recTypeString = "HBR"; break;
          case SBR: recTypeString = "SBR"; break;
          case PMR: recTypeString = "PMR"; break;
          case PGR: recTypeString = "PGR"; break;
          case PLR: recTypeString = "PLR"; break;
          case RDR: recTypeString = "RDR"; break;
          case SDR: recTypeString = "SDR"; break;
          case WIR: recTypeString = "WIR"; break;
          case WRR: recTypeString = "WRR"; break;
          case WCR: recTypeString = "WCR"; break;
          case PIR: recTypeString = "PIR"; break;
          case PRR: recTypeString = "PRR"; break;
          case TSR: recTypeString = "TSR"; break;
          case PTR: recTypeString = "PTR"; break;
          case MPR: recTypeString = "MPR"; break;
          case FTR: recTypeString = "FTR"; break;
          case BPS: recTypeString = "BPS"; break;
          case EPS: recTypeString = "EPS"; break;
          case GDR: recTypeString = "GDR"; break;
          case DTR: recTypeString = "DTR"; break;
            default: recTypeString = "";
        };

        return recTypeString;
    }


    RecordTypeCodeMap RecordHeader::codeMap;
    map<unsigned int, RecordType> RecordHeader::codeToTypeMap;

    RecordHeader::RecordHeader( U1 _type, U1 _subType, U2 _len) {
        // TODO add error check for invalid type and subType
        length = _len;
        type = _type;
        subType = _subType;
    }

    RecordHeader::RecordHeader( RecordType recType) {
        recordTypeToTypes( recType, type, subType);
    }

    RecordHeader& RecordHeader::operator=(RecordType& recType) {
        recordTypeToTypes( recType, type, subType);
        return *this;
    }

    void RecordHeader::recordTypeToTypes( const RecordType& rec, U1& type, U1 & subType) {
        if(codeMap.size() == 0) {
            // Information about the STDF file
            codeMap[FAR] = make_pair( 0, 10);
            codeMap[ATR] = make_pair( 0, 20);

            // Data collected on a per lot basis
            codeMap[MIR] = make_pair( 1, 10);
            codeMap[MRR] = make_pair( 1, 20);
            codeMap[PCR] = make_pair( 1, 30);
            codeMap[HBR] = make_pair( 1, 40);
            codeMap[SBR] = make_pair( 1, 50);
            codeMap[PMR] = make_pair( 1, 60);
            codeMap[PGR] = make_pair( 1, 62);
            codeMap[PLR] = make_pair( 1, 63);
            codeMap[RDR] = make_pair( 1, 70);
            codeMap[SDR] = make_pair( 1, 80);

            // Data collected per wafer
            codeMap[WIR] = make_pair( 2, 10);
            codeMap[WRR] = make_pair( 2, 20);
            codeMap[WCR] = make_pair( 2, 30);

            // Data collected on a per part basis
            codeMap[PIR] = make_pair( 5, 10);
            codeMap[PRR] = make_pair( 5, 20);

            // Data collected per test in the test program
            codeMap[TSR] = make_pair( 10, 30);

            // Data collected per test execution
            codeMap[PTR] = make_pair( 15, 10);
            codeMap[MPR] = make_pair( 15, 15);
            codeMap[FTR] = make_pair( 15, 20);

            // Data collected per program segment
            codeMap[BPS] = make_pair( 20, 10);
            codeMap[EPS] = make_pair( 20, 20);

            // Generic Data
            codeMap[GDR] = make_pair( 50, 10);
            codeMap[DTR] = make_pair( 50, 30);

        }

        RecordTypeCodeMap::iterator iter = codeMap.find(rec);
        if(iter != codeMap.end()) {
            type = iter->second.first;
            subType = iter->second.second;
        }

        return;
    }

    RecordType RecordHeader::getRecordType()
    {
        if(codeToTypeMap.size() == 0) {
            codeToTypeMap[ (unsigned int) FAR ] = FAR;
            codeToTypeMap[ (unsigned int) ATR ] = ATR;
            codeToTypeMap[ (unsigned int) MIR ] = MIR;
            codeToTypeMap[ (unsigned int) MRR ] = MRR;
            codeToTypeMap[ (unsigned int) PCR ] = PCR;
            codeToTypeMap[ (unsigned int) HBR ] = HBR;
            codeToTypeMap[ (unsigned int) SBR ] = SBR;
            codeToTypeMap[ (unsigned int) PMR ] = PMR;
            codeToTypeMap[ (unsigned int) PGR ] = PGR;
            codeToTypeMap[ (unsigned int) PLR ] = PLR;
            codeToTypeMap[ (unsigned int) RDR ] = RDR;
            codeToTypeMap[ (unsigned int) SDR ] = SDR;
            codeToTypeMap[ (unsigned int) WIR ] = WIR;
            codeToTypeMap[ (unsigned int) WRR ] = WRR;
            codeToTypeMap[ (unsigned int) WCR ] = WCR;
            codeToTypeMap[ (unsigned int) PIR ] = PIR;
            codeToTypeMap[ (unsigned int) PRR ] = PRR;
            codeToTypeMap[ (unsigned int) TSR ] = TSR;
            codeToTypeMap[ (unsigned int) PTR ] = PTR;
            codeToTypeMap[ (unsigned int) MPR ] = MPR;
            codeToTypeMap[ (unsigned int) FTR ] = FTR;
            codeToTypeMap[ (unsigned int) BPS ] = BPS;
            codeToTypeMap[ (unsigned int) EPS ] = EPS;
            codeToTypeMap[ (unsigned int) GDR ] = GDR;
            codeToTypeMap[ (unsigned int) DTR ] = DTR;
        }

        RecordType recordType = Header;
        map<unsigned int, RecordType>::iterator iter = codeToTypeMap.find((unsigned int) type*100 + (unsigned int) subType);
        if(iter != codeToTypeMap.end()) {
            recordType = iter->second;
        }
        else {
            std::cout << "Did not find Type : " << (unsigned int) type << " SubType : " << (unsigned int) subType << endl;
        }
        return recordType;
    }

    string RecordHeader::getRecordTypeString() {
        // Call this to build the map
        RecordType recType = getRecordType();

        string recTypeString;
        switch(recType) {
          case FAR: recTypeString = "FAR"; break;
          case ATR: recTypeString = "ATR"; break;
          case MIR: recTypeString = "MIR"; break;
          case MRR: recTypeString = "MRR"; break;
          case PCR: recTypeString = "PCR"; break;
          case HBR: recTypeString = "HBR"; break;
          case SBR: recTypeString = "SBR"; break;
          case PMR: recTypeString = "PMR"; break;
          case PGR: recTypeString = "PGR"; break;
          case PLR: recTypeString = "PLR"; break;
          case RDR: recTypeString = "RDR"; break;
          case SDR: recTypeString = "SDR"; break;
          case WIR: recTypeString = "WIR"; break;
          case WRR: recTypeString = "WRR"; break;
          case WCR: recTypeString = "WCR"; break;
          case PIR: recTypeString = "PIR"; break;
          case PRR: recTypeString = "PRR"; break;
          case TSR: recTypeString = "TSR"; break;
          case PTR: recTypeString = "PTR"; break;
          case MPR: recTypeString = "MPR"; break;
          case FTR: recTypeString = "FTR"; break;
          case BPS: recTypeString = "BPS"; break;
          case EPS: recTypeString = "EPS"; break;
          case GDR: recTypeString = "GDR"; break;
          case DTR: recTypeString = "DTR"; break;
            default: recTypeString = "";
        };

        return recTypeString;
    }

    ostream& operator<<(ostream& os, RecordHeader& rh) {
        string sep = "\t";
        return os << "RecordHeader" << endl
               << sep << "Length: " << (int) rh.length << endl
               << sep << "Type: " << (int) rh.type << endl
               << sep << "Type: " << rh.getRecordTypeString() << endl
               << sep << "SubType: " << (int) rh.subType << endl;
               //<< sep << "Enum: " << rh.getRecordType();
    }

    Record::Record() : recordHeader(Header) {
    }

    string Record::sep = "\t";

    ostream& operator<<(ostream& os, Record& rh) {
        string sep = rh.sep;
        vector< pair<string,string> > fields;
        rh.getFields( fields);

        os << recordTypeToString(rh.getRecordType()) << endl;
        for(unsigned int i=0; i < fields.size(); i++)
            os << sep << fields[i].first << ": " << sep << fields[i].second << endl;
        return os;
    }

    FARRecord::FARRecord(U1 cpu, U1 version) {
        recordHeader = FAR;
        cpuType     = cpu;
        stdfVersion = version;
    }

    void FARRecord::getFields( vector<pair<string, string> >& fields) {
        stringstream sstr;
        string value;

        sstr << (int) cpuType;
        sstr >> value;
        fields.push_back( make_pair( "CpuType", value));

        sstr << (int) stdfVersion;
        sstr >> value;
        fields.push_back( make_pair( "StdfVersion", value));
    }

/*
    void FARRecord::print(ostream& os, bool detailed) {
        os << "FAR" << endl;
        if(detailed) {
            os << sep << "CpuType : " << (int) cpuType << endl;
            os << sep << "StdfVersion : " << (int) stdfVersion << endl;
        }
    }
*/

    ByteOrder FARRecord::getByteOrder() {
        ByteOrder byteOrder;

        switch(cpuType) {
            case 0: byteOrder = PDPEndian; break;
            case 1: byteOrder = BigEndian; break;
            case 2: byteOrder = LittleEndian; break;
            default: byteOrder = NotDefined; break;
        };

        return byteOrder;
    }

    ATRRecord::ATRRecord() {
        recordHeader = ATR;
        modificationTime = 0;
        commandLine = "";
    }

    ATRRecord::ATRRecord( U4 modTime, CN cmdLine) {
        recordHeader = ATR;
        modificationTime = modTime;
        commandLine      = cmdLine;
    }

    void ATRRecord::getFields( vector<pair<string, string> >& fields) {
        fields.push_back( make_pair( "ModificationTime", time2string(modificationTime)));
        fields.push_back( make_pair( "CommandLine",      commandLine.str()));
    }

    MIRRecord::MIRRecord() {
        recordHeader = MIR;

        time_t currTime = time(NULL);
        startTime = setupTime = currTime;

        modeCode = retestCode = protectionCode = commandModeCode = ' ';
    }

    U2 MIRRecord::getLength(void) {
        U2 len = 0;

        len += 4 + 4 + 1 + 1 + 1 + 1 + 2 + 1;
        len += lotID.getLength();
        len += partType.getLength();
        len += nodeName.getLength();
        len += testerType.getLength();
        len +=  jobName.getLength();
        len +=  jobRevision.getLength();
        len +=  sublotID.getLength();
        len +=  operatorName.getLength();
        len +=  executiveType.getLength();
        len +=  executiveVersion.getLength();
        len +=  testCode.getLength();
        len +=  testTemp.getLength();
        len +=  userText.getLength();
        len +=  auxFile.getLength();
        len +=  packageType.getLength();
        len +=  familyID.getLength();
        len +=  dateCode.getLength();
        len +=  facilityID.getLength();
        len +=  floorID.getLength();
        len +=  processID.getLength();
        len +=  operatorFrequency.getLength();
        len +=  specName.getLength();
        len +=  specVersion.getLength();
        len +=  flowID.getLength();
        len +=  setupID.getLength();
        len +=  designRevision.getLength();
        len +=  engineeringLotID.getLength();
        len +=  romCode.getLength();
        len +=  serialNumber.getLength();
        len +=  supervisorName.getLength();

        return len;
    }

    void MIRRecord::getFields( vector<pair<string, string> >& fields) {
        stringstream sstr;

        fields.push_back( make_pair( "SetupTime",        time2string(setupTime)));
        fields.push_back( make_pair( "StartTime",        time2string(startTime)));
        fields.push_back( make_pair( "StationNumber",    toString(stationNumber)));
        fields.push_back( make_pair( "ModeCode",         toString(modeCode)));
        fields.push_back( make_pair( "RetestCode",       toString(retestCode)));
        fields.push_back( make_pair( "ProtectionCode",   toString(protectionCode)));
        fields.push_back( make_pair( "BurninTime",       toString(burninTime)));
        fields.push_back( make_pair( "CommandModeCode",  toString(commandModeCode)));
        fields.push_back( make_pair( "LotID",            lotID.str()));
        fields.push_back( make_pair( "PartType",         partType.str()));
        fields.push_back( make_pair( "NodeName",         nodeName.str()));
        fields.push_back( make_pair( "TesterType",       testerType.str()));
        fields.push_back( make_pair( "JobName",          jobName.str()));
        fields.push_back( make_pair( "JobRevision",      jobRevision.str()));
        fields.push_back( make_pair( "SublotID",         sublotID.str()));
        fields.push_back( make_pair( "OperatorName",     operatorName.str()));
        fields.push_back( make_pair( "ExecutiveType",    executiveType.str()));
        fields.push_back( make_pair( "ExecutiveVersion", executiveVersion.str()));
        fields.push_back( make_pair( "TestCode",         testCode.str()));
        fields.push_back( make_pair( "TestTemp",         testTemp.str()));
        fields.push_back( make_pair( "UserText",         userText.str()));
        fields.push_back( make_pair( "AuxFile",          auxFile.str()));
        fields.push_back( make_pair( "PackageType",      packageType.str()));
        fields.push_back( make_pair( "FamilyID",         familyID.str()));
        fields.push_back( make_pair( "DateCode",         dateCode.str()));
        fields.push_back( make_pair( "FacilityID",       facilityID.str()));
        fields.push_back( make_pair( "FloorID",          floorID.str()));
        fields.push_back( make_pair( "ProcessID",        toString(processID)));
        fields.push_back( make_pair( "operatorFrequency",	toString(operatorFrequency)));
        fields.push_back( make_pair( "specName",	toString(specName)));
        fields.push_back( make_pair( "specVersion",	toString(specVersion)));
        fields.push_back( make_pair( "flowID",	toString(flowID)));
        fields.push_back( make_pair( "setupID",	toString(setupID)));
        fields.push_back( make_pair( "designRevision",	toString(designRevision)));
        fields.push_back( make_pair( "engineeringLotID",	toString(engineeringLotID)));
        fields.push_back( make_pair( "romCode",	toString(romCode)));
        fields.push_back( make_pair( "serialNumber",	toString(serialNumber)));
        fields.push_back( make_pair( "supervisorName",	toString(supervisorName)));

        // TODO
    }

    /////////////////////////////////////////////////////////////////////////////
    MRRRecord::MRRRecord() {
        recordHeader = MRR;

        time_t currTime = time(NULL);
        finishTime      = currTime;
        dispositionCode = ' ';
    }

    U2 MRRRecord::getLength(void) {
        U2 len = 0;
        len += 4;
        len += 1;
        len += userLotDescription.getLength();
        len += executiveLotDescription.getLength();

        return len;
    }

    void MRRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "FinishTime",               time2string(finishTime)));
        fields.push_back( make_pair( "DispositionCode",          toString(dispositionCode)));
        fields.push_back( make_pair( "User LotDescription",      toString(userLotDescription)));
        fields.push_back( make_pair( "Executive LotDescription", toString(executiveLotDescription)));
    }

    ////////////////////////////////////////////////////////////////////////////
    PCRRecord::PCRRecord() {
        recordHeader = PCR;
        headNumber   = 0;
        siteNumber   = 0;

        partCount    = 0;
        retestCount  = abortCount = goodCount = funcCount = 4294967295U;
    }

    U2 PCRRecord::getLength(void) {
        U2 len = 1 + 1 + 4 + 4 + 4 + 4 + 4;
        return len;
    }

    void PCRRecord::getFields( vector< pair<string, string> >& fields) {
        fields.push_back( make_pair( "HeadNumber",  toString(headNumber)));
        fields.push_back( make_pair( "SiteNumber",  toString(siteNumber)));
        fields.push_back( make_pair( "PartCount",   toString(partCount)));
        fields.push_back( make_pair( "RetestCount", toString(retestCount)));
        fields.push_back( make_pair( "AbortCount",  toString(abortCount)));
        fields.push_back( make_pair( "GoodCount",   toString(goodCount)));
        fields.push_back( make_pair( "FuncCount",   toString(funcCount)));
    }

    /////////////////////////////////////////////////////////////////////////////
    SDRRecord::SDRRecord() {
        recordHeader = SDR;
        headNumber = 0;
        siteGroup = 0;
        siteCount = 0;
        extraID = "";

    }

    U2 SDRRecord::getLength(void) {
        U2 len = 0;

        len += 1; // U1 headNumber
        len += 1; // U1 siteGroup
        len += 1; // U1 siteCount
        len += siteNumbers.size(); // U1 siteNumbers
        len += handlerType.getLength(); // CN handlerType
        len += handlerID.getLength(); // CN handlerID
        len += probeCardType.getLength(); // CN probeCardType
        len += probeCardID.getLength(); // CN probeCardID
        len += loadBoardType.getLength(); // CN loadBoardType
        len += loadBoardID.getLength(); // CN loadBoardID
        len += dibType.getLength(); // CN dibType
        len += dibID.getLength(); // CN dibID
        len += cableType.getLength(); // CN cableType
        len += cableID.getLength(); // CN cableID
        len += contactorType.getLength(); // CN contactorType
        len += contactorID.getLength(); // CN contactorID
        len += laserType.getLength(); // CN laserType
        len += laserID.getLength(); // CN laserID
        len += extraType.getLength(); // CN extraType
        len += extraID.getLength(); // CN extraID

        return len;
    }

    void SDRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteGroup",	toString(siteGroup)));
        fields.push_back( make_pair( "siteCount",	toString(siteCount)));
        fields.push_back( make_pair( "siteNumbers",	toString(siteNumbers)));
        fields.push_back( make_pair( "handlerType",	toString(handlerType)));
        fields.push_back( make_pair( "handlerID",	toString(handlerID)));
        fields.push_back( make_pair( "probeCardType",	toString(probeCardType)));
        fields.push_back( make_pair( "probeCardID",	toString(probeCardID)));
        fields.push_back( make_pair( "loadBoardType",	toString(loadBoardType)));
        fields.push_back( make_pair( "loadBoardID",	toString(loadBoardID)));
        fields.push_back( make_pair( "dibType",	toString(dibType)));
        fields.push_back( make_pair( "dibID",	toString(dibID)));
        fields.push_back( make_pair( "cableType",	toString(cableType)));
        fields.push_back( make_pair( "cableID",	toString(cableID)));
        fields.push_back( make_pair( "contactorType",	toString(contactorType)));
        fields.push_back( make_pair( "contactorID",	toString(contactorID)));
        fields.push_back( make_pair( "laserType",	toString(laserType)));
        fields.push_back( make_pair( "laserID",	toString(laserID)));
        fields.push_back( make_pair( "extraType",	toString(extraType)));
        fields.push_back( make_pair( "extraID",	toString(extraID)));

    }


    /////////////////////////////////////////////////////////////////////////////
    PMRRecord::PMRRecord() {
        recordHeader = PMR;
        pmrIndex = 0;
        channelType = 0;
        siteNumber = 1;
        headNumber = 1;
    }

    U2 PMRRecord::getLength(void) {
        U2 len = 0;
        len += 2; // U2 pmrIndex
        len += 2; // U2 channelType
        len += channelName.getLength(); // CN channelName
        len += physicalName.getLength(); // CN physicalName
        len += logicalName.getLength(); // CN logicalName
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber

        return len;
    }

    void PMRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "pmrIndex",	toString(pmrIndex)));
        fields.push_back( make_pair( "channelType",	toString(channelType)));
        fields.push_back( make_pair( "channelName",	toString(channelName)));
        fields.push_back( make_pair( "physicalName",	toString(physicalName)));
        fields.push_back( make_pair( "logicalName",	toString(logicalName)));
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));

    }

    /////////////////////////////////////////////////////////////////////////////
    PGRRecord::PGRRecord() {
        recordHeader = PGR;

        groupIndex = 0;
        indexCount = 0;
    }

    U2 PGRRecord::getLength(void) {
        U2 len = 0;
        len += 2; // U2 groupIndex
        len += groupName.getLength(); // CN groupName
        len += 2; // U2 indexCount
        len += (pmrIndex.size() * 2); // U2 pmrIndex

        return len;
    }

    void PGRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "groupIndex",	toString(groupIndex)));
        fields.push_back( make_pair( "groupName",	toString(groupName)));
        fields.push_back( make_pair( "indexCount",	toString(indexCount)));
        fields.push_back( make_pair( "pmrIndex",	toString(pmrIndex)));

    }


    /////////////////////////////////////////////////////////////////////////////
    PIRRecord::PIRRecord() {
        recordHeader = PIR;
        siteNumber = 1;
        headNumber = 1;

    }

    U2 PIRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber

        return len;
    }

    void PIRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));

    }


    /////////////////////////////////////////////////////////////////////////////
    PLRRecord::PLRRecord() {
        recordHeader = PLR;
        groupCount = 0;
    }

    U2 PLRRecord::getLength(void) {
        U2 len = 0;
        len += 2; // U2 groupCount
        len += 2 * groupCount; // U2 groupIndex
        len += 2 * groupCount; // U2 groupMode
        len += 1 * groupCount; // U1 groupRadix
        for(unsigned int i=0; i < groupCount; i++) {
            len += programCharRight[i].getLength(); // CN programCharRight
            len += returnCharRight[i].getLength(); // CN returnCharRight
            len += programCharLeft[i].getLength(); // CN programCharLeft
            len += returnCharLeft[i].getLength(); // CN returnCharLeft
        }

        return len;
    }

    void PLRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "groupCount",	toString(groupCount)));
        fields.push_back( make_pair( "groupIndex",	toString(groupIndex)));
        fields.push_back( make_pair( "groupMode",	toString(groupMode)));
        fields.push_back( make_pair( "groupRadix",	toString(groupRadix)));
        fields.push_back( make_pair( "programCharRight",	toString(programCharRight)));
        fields.push_back( make_pair( "returnCharRight",	toString(returnCharRight)));
        fields.push_back( make_pair( "programCharLeft",	toString(programCharLeft)));
        fields.push_back( make_pair( "returnCharLeft",	toString(returnCharLeft)));
    }



    /////////////////////////////////////////////////////////////////////////////
    PTRRecord::PTRRecord() {
        recordHeader = PTR;
        optFlag      = 0xFF;
        testNumber   = 0;
        headNumber   = 1;
        siteNumber   = 1;
        testFlag     = 0x52; // 8'b01010010
        parmFlag     = 0;
        testResult   = 0.0;
        loLimit      = 0.0;
        hiLimit      = 0.0;
        loSpec       = 0.0;
        hiSpec       = 0.0;
        resultScale  = 0;
        llmScale     = 0;
        hlmScale     = 0;
    }

    U2 PTRRecord::getLength(void) {
        U2 len = 0;
        len += 4; // U4 testNumber
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber
        len += 1; // B1 testFlag
        len += 1; // B1 parmFlag
        len += 4; // R4 testResult
        len += testText.getLength(); // CN testText
        len += alarmID.getLength(); // CN alarmID
        len += 1; // B1 optFlag
        if(optFlag != 0xFF) {
            len += 1; // I1 resultScale
            len += 1; // I1 llmScale
            len += 1; // I1 hlmScale
            len += 4; // R4 loLimit
            len += 4; // R4 hiLimit
            len += units.getLength(); // CN units
            len += cResFmt.getLength(); // CN cResFmt
            len += cLlmFmt.getLength(); // CN cLlmFmt
            len += cHlmFmt.getLength(); // CN cHlmFmt
            len += 4; // R4 loSpec
            len += 4; // R4 hiSpec
        }

        return len;
    }

    void PTRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "testNumber",	toString(testNumber)));
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));
        fields.push_back( make_pair( "testFlag",	toString(testFlag)));
        fields.push_back( make_pair( "parmFlag",	toString(parmFlag)));
        fields.push_back( make_pair( "testResult",	toString(testResult)));
        fields.push_back( make_pair( "testText",	toString(testText)));
        fields.push_back( make_pair( "alarmID",	toString(alarmID)));
        fields.push_back( make_pair( "optFlag",	toString(optFlag)));
        fields.push_back( make_pair( "resultScale",	toString(resultScale)));
        fields.push_back( make_pair( "llmScale",	toString(llmScale)));
        fields.push_back( make_pair( "hlmScale",	toString(hlmScale)));
        fields.push_back( make_pair( "loLimit",	toString(loLimit)));
        fields.push_back( make_pair( "hiLimit",	toString(hiLimit)));
        fields.push_back( make_pair( "units",	toString(units)));
        fields.push_back( make_pair( "cResFmt",	toString(cResFmt)));
        fields.push_back( make_pair( "cLlmFmt",	toString(cLlmFmt)));
        fields.push_back( make_pair( "cHlmFmt",	toString(cHlmFmt)));
        fields.push_back( make_pair( "loSpec",	toString(loSpec)));
        fields.push_back( make_pair( "hiSpec",	toString(hiSpec)));

    }

    /////////////////////////////////////////////////////////////////////////////
    PRRRecord::PRRRecord() {
        recordHeader = PRR;
        //partFix = "";
        partFlag = 0;
        numTests = 0;
        hardBin = softBin = 65535;
        xCoord = yCoord = -32768;
        testTime = 0;

    }

    U2 PRRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber
        len += 1; // B1 partFlag
        len += 2; // U2 numTests
        len += 2; // U2 hardBin
        len += 2; // U2 softBin
        len += 2; // I2 xCoord
        len += 2; // I2 yCoord
        len += 4; // U4 testTime
        len += partID.getLength(); // CN partID
        len += partText.getLength(); // CN partText
        len += partFix.getLength(); // BN partFix

        return len;
    }

    void PRRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));
        fields.push_back( make_pair( "partFlag",	toString(partFlag)));
        fields.push_back( make_pair( "numTests",	toString(numTests)));
        fields.push_back( make_pair( "hardBin",	toString(hardBin)));
        fields.push_back( make_pair( "softBin",	toString(softBin)));
        fields.push_back( make_pair( "xCoord",	toString(xCoord)));
        fields.push_back( make_pair( "yCoord",	toString(yCoord)));
        fields.push_back( make_pair( "testTime",	toString(testTime)));
        fields.push_back( make_pair( "partID",	toString(partID)));
        fields.push_back( make_pair( "partText",	toString(partText)));
        fields.push_back( make_pair( "partFix",	toString(partFix)));
    }

    /////////////////////////////////////////////////////////////////////////////
    TSRRecord::TSRRecord() {
        recordHeader = TSR;
        testSquares = 0;

    }

    U2 TSRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber
        len += 1; // C1 testType
        len += 4; // U4 testNumber
        len += 4; // U4 execCount
        len += 4; // U4 failCount
        len += 4; // U4 alarmCount
        len += testName.getLength(); // CN testName
        len += sequencerName.getLength(); // CN sequencerName
        len += testLabel.getLength(); // CN testLabel
        len += 1; // B1 optFlag
        len += 4; // R4 testTime
        len += 4; // R4 testMin
        len += 4; // R4 testMax
        len += 4; // R4 testSums
        len += 4; // R4 testSquares

        return len;
    }

    void TSRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));
        fields.push_back( make_pair( "testType",	toString(testType)));
        fields.push_back( make_pair( "testNumber",	toString(testNumber)));
        fields.push_back( make_pair( "execCount",	toString(execCount)));
        fields.push_back( make_pair( "failCount",	toString(failCount)));
        fields.push_back( make_pair( "alarmCount",	toString(alarmCount)));
        fields.push_back( make_pair( "testName",	toString(testName)));
        fields.push_back( make_pair( "sequencerName",	toString(sequencerName)));
        fields.push_back( make_pair( "testLabel",	toString(testLabel)));
        fields.push_back( make_pair( "optFlag",	toString(optFlag)));
        fields.push_back( make_pair( "testTime",	toString(testTime)));
        fields.push_back( make_pair( "testMin",	toString(testMin)));
        fields.push_back( make_pair( "testMax",	toString(testMax)));
        fields.push_back( make_pair( "testSums",	toString(testSums)));
        fields.push_back( make_pair( "testSquares",	toString(testSquares)));
    }



    /////////////////////////////////////////////////////////////////////////////
    WCRRecord::WCRRecord() {
        recordHeader = WCR;
        positiveY = ' ';

    }

    U2 WCRRecord::getLength(void) {
        U2 len = 0;
        len += 4; // R4 waferSize
        len += 4; // R4 dieHeight
        len += 4; // R4 dieWidth
        len += 1; // U1 waferUnits
        len += 1; // C1 waferFlat
        len += 2; // I2 centerX
        len += 2; // I2 centerY
        len += 1; // C1 positiveX
        len += 1; // C1 positiveY

        return len;
    }

    void WCRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "waferSize",	toString(waferSize)));
        fields.push_back( make_pair( "dieHeight",	toString(dieHeight)));
        fields.push_back( make_pair( "dieWidth",	toString(dieWidth)));
        fields.push_back( make_pair( "waferUnits",	toString(waferUnits)));
        fields.push_back( make_pair( "waferFlat",	toString(waferFlat)));
        fields.push_back( make_pair( "centerX",	toString(centerX)));
        fields.push_back( make_pair( "centerY",	toString(centerY)));
        fields.push_back( make_pair( "positiveX",	toString(positiveX)));
        fields.push_back( make_pair( "positiveY",	toString(positiveY)));

    }



    /////////////////////////////////////////////////////////////////////////////
    WIRRecord::WIRRecord() {
        recordHeader = WIR;
        waferID = "";

    }

    U2 WIRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteGroup
        len += 4; // U4 startTime
        len += waferID.getLength(); // CN waferID

        return len;
    }

    void WIRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteGroup",	toString(siteGroup)));
        fields.push_back( make_pair( "startTime",	toString(startTime)));
        fields.push_back( make_pair( "waferID",	toString(waferID)));

    }



    /////////////////////////////////////////////////////////////////////////////
    WRRRecord::WRRRecord() {
        recordHeader = WRR;
        execDescription = "";

    }

    U2 WRRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteGroup
        len += 4; // U4 finishTime
        len += 4; // U4 partCount
        len += 4; // U4 retestCount
        len += 4; // U4 abortCount
        len += 4; // U4 goodCount
        len += 4; // U4 funcCount
        len += waferID.getLength(); // CN waferID
        len += fabWaferID.getLength(); // CN fabWaferID
        len += waferFrameID.getLength(); // CN waferFrameID
        len += waferMaskID.getLength(); // CN waferMaskID
        len += userDescription.getLength(); // CN userDescription
        len += execDescription.getLength(); // CN execDescription

        return len;
    }

    void WRRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteGroup",	toString(siteGroup)));
        fields.push_back( make_pair( "finishTime",	toString(finishTime)));
        fields.push_back( make_pair( "partCount",	toString(partCount)));
        fields.push_back( make_pair( "retestCount",	toString(retestCount)));
        fields.push_back( make_pair( "abortCount",	toString(abortCount)));
        fields.push_back( make_pair( "goodCount",	toString(goodCount)));
        fields.push_back( make_pair( "funcCount",	toString(funcCount)));
        fields.push_back( make_pair( "waferID",	toString(waferID)));
        fields.push_back( make_pair( "fabWaferID",	toString(fabWaferID)));
        fields.push_back( make_pair( "waferFrameID",	toString(waferFrameID)));
        fields.push_back( make_pair( "waferMaskID",	toString(waferMaskID)));
        fields.push_back( make_pair( "userDescription",	toString(userDescription)));
        fields.push_back( make_pair( "execDescription",	toString(execDescription)));

    }


    /////////////////////////////////////////////////////////////////////////////
    HBRRecord::HBRRecord() {
        recordHeader = HBR;
        hbinName = "";

    }

    U2 HBRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber
        len += 2; // U2 hbinNumber
        len += 4; // U4 hbinCount
        len += 1; // C1 hbinPF
        len += hbinName.getLength(); // CN hbinName

        return len;
    }

    void HBRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));
        fields.push_back( make_pair( "hbinNumber",	toString(hbinNumber)));
        fields.push_back( make_pair( "hbinCount",	toString(hbinCount)));
        fields.push_back( make_pair( "hbinPF",	toString(hbinPF)));
        fields.push_back( make_pair( "hbinName",	toString(hbinName)));
    }

    /////////////////////////////////////////////////////////////////////////////
    SBRRecord::SBRRecord() {
        recordHeader = SBR;
        sbinName = "";

    }

    U2 SBRRecord::getLength(void) {
        U2 len = 0;
        len += 1; // U1 headNumber
        len += 1; // U1 siteNumber
        len += 2; // U2 sbinNumber
        len += 4; // U4 sbinCount
        len += 1; // C1 sbinPF
        len += sbinName.getLength(); // CN sbinName

        return len;
    }

    void SBRRecord::getFields( vector< pair<string,string> >& fields) {
        fields.push_back( make_pair( "headNumber",	toString(headNumber)));
        fields.push_back( make_pair( "siteNumber",	toString(siteNumber)));
        fields.push_back( make_pair( "sbinNumber",	toString(sbinNumber)));
        fields.push_back( make_pair( "sbinCount",	toString(sbinCount)));
        fields.push_back( make_pair( "sbinPF",	toString(sbinPF)));
        fields.push_back( make_pair( "sbinName",	toString(sbinName)));

    }

} // end namespace
